import cmStyleMixin from '@/mixins/cmStyle.js'
import commonMixin from '@/mixins/common.js'

/*
  @slot 插槽
  default 遮罩主体区域内容
*/

export default {
  name: 'cm-popup',
  mixins: [
    cmStyleMixin,
    commonMixin
  ],
  props: {
    // 弹出方向：left / top / bottom / right / center
    direction: {
      default: 'center',
      type: String
    },
    // 点击遮罩层关闭
    maskClosed: {
      default: true,
      type: Boolean
    },
    // 宽度，在 left / right / center 时有效，CSS属性
    width: {
      default: 'auto',
      type: [Number, String]
    },
    // 高度，在 top / bottom / center 时有效
    height: {
      default: 'auto',
      type: [Number, String]
    },
    // 动画时间，最小1000
    duration: {
      default: 300,
      type: [Number, String],
    },
    // 初始是否生成，若为true则早已生成弹框元素，为false则在第一次弹起时才生成弹框元素
    exist: {
      default: false,
      type: Boolean
    }
  },
  data () {
    return {
      // 系统状态栏和标题栏高度，遮罩层不应该把系统栏也覆盖掉
      StatusBar: this.StatusBar,
      CustomBar: this.CustomBar,
      
      // 是否生成
      isExist: this.exist,
      // 是否首次显示
      isFirstShow: true,
      // 是否显示
      isShow: false,
      // 动画是否正在播放
      isAnimating: false,
      // 动画状态
      aniState: 'none',
      // 计时器
      timer: null,
      // 弹框主体的class
      popClass: `popup-${this.direction}`,
    }
  },
  computed: {
    // 弹框主体的样式
    popStyle () {
      // 动画元素初始设定
      let style = {
        animationDuration: this.duration + 'ms',
      }
      if (this.direction === 'left' || this.direction === 'right' || this.direction === 'center') {
        style.width = this.width
      }
      if (this.direction === 'top' || this.direction === 'bottom' || this.direction === 'center') {
        style.height = this.height
      }
      return style
    },
    
    // 弹框容器外部样式类
    wrapperClass () {
      return [
        this.direction === 'center' ? 'cm-flex cm-flex-col cm-flex-j-center cm-flex-a-center' : '',
        this.isShow ? '' : 'cm-popup-none'
      ].join(' ')
    },
    
    
    // 弹框动画类
    aniClass () {
      return 'cm-animation ' + (this.direction === 'center' ? `zoom-${this.aniState}` : `slide-${this.direction}-${this.aniState}`)
    },
    
    // 遮罩层动画类
    coverAniClass () {
      return `cm-animation fade-${this.aniState}`
    }
  },
  methods: {
    // 阻止遮罩层事件穿透的空函数
    moveHandler () {},
    
    // 阻止遮罩层点击事件穿透
    clickHandler () {},
    
    // 点击遮罩层
    coverClickHandler () {
      if (this.maskClosed) {
        this.hide()
      }
    },
    
    /* 
      显示弹框
      callback 完成动画回调函数
      specialCallback 特殊回调函数，祖传代码，用于处理第一次初始化值的BUG
      在弹框首次弹出时，在动画完成后执行回调
      之后，在动画完成前执行
      祖传代码！！！！！！！！！！！！！！！！！！！！！！！！！！
    */
    show (callback = () => {}, specialCallback = () => {}) {
      if (this.aniState === 'none') {
        // 只有在动画播放完成后才能触发
        if (!this.isExist) {
          this.isExist = true
        }

        // 若不是首次弹出，则特殊回调函数在动画前触发
        if (!this.isFirstShow && typeof specialCallback === 'function') {
          specialCallback()
        }
        
        // 触发弹入动画
        this.$nextTick(() => {
          this.isShow = true
          this.aniState = 'in'
          this.wait(this.duration, 'popup-ani').then(() => {
            // 动画完成，关闭互斥锁
            this.aniState = 'none'
            
            if (this.isFirstShow && typeof specialCallback === 'function') {
              // 首次弹出，则特殊回调函数在动画后触发
              specialCallback()
            }
            // 首次弹出标记置false
            this.isFirstShow = false
            
            // 完成动画回调函数
            if (typeof callback === 'function') {
              callback()
            }
          })
          .catch((e) => {
            console.log(e)
          })
        })
      }
    },
    
    // 隐藏弹框
    hide (callback = () => {}) {
      if (this.aniState === 'none') {
        // 只有在动画播放完成后才能触发
        // 触发弹出动画
        this.aniState = 'out'
        
        this.wait(this.duration, 'popup-ani').then(() => {
          // 动画完成，关闭互斥锁
          this.aniState = 'none'
          // 隐藏弹框
          this.isShow = false
          // 完成动画回调函数
          if (typeof callback === 'function') {
            callback()
          }
        })
        .catch((e) => {
          console.log(e)
        })
      }
    }
  }
}